/**
 * 
 */
package org.jenkon.commons.collection.map;

import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;

/**
 * @author Jens Konopka
 * 
 * @param <K> the type of key
 * @param <V> the type of value
 */
public class CompositeMap<K, V> implements Map<K, V> {

	/**
	 * {@link Collection} with all {@link Map} objects.
	 */
	private final Collection<Map<K, V>> maps = new ArrayList<Map<K, V>>();

	/**
	 * @param map {@link Map} to add {@link #maps}
	 */
	public void add(final Map<K, V> map) {
		maps.add(map);
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see java.util.Map#size()
	 */
	public int size() {
		int size = 0;
		for (final Map<K, V> map : maps) {
			size += map.size();
		}
		return size;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see java.util.Map#isEmpty()
	 */
	public boolean isEmpty() {
		for (final Map<K, V> map : maps) {
			if (!map.isEmpty()) {
				return false;
			}
		}
		return true;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see java.util.Map#containsKey(java.lang.Object)
	 */
	public boolean containsKey(final Object key) {
		for (final Map<K, V> map : maps) {
			if (map.containsKey(key)) {
				return true;
			}
		}
		return false;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see java.util.Map#containsValue(java.lang.Object)
	 */
	public boolean containsValue(final Object value) {
		for (final Map<K, V> map : maps) {
			if (map.containsValue(value)) {
				return true;
			}
		}
		return false;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see java.util.Map#get(java.lang.Object)
	 */
	public V get(final Object key) {
		for (final Map<K, V> map : maps) {
			if (map.containsKey(key)) {
				return map.get(key);
			}
		}
		return null;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see java.util.Map#put(java.lang.Object, java.lang.Object)
	 */
	public V put(final K key, final V value) {
		throw new UnsupportedOperationException("the put() method was not supported");
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see java.util.Map#remove(java.lang.Object)
	 */
	public V remove(final Object key) {
		for (final Map<K, V> map : maps) {
			if (map.containsKey(key)) {
				return map.remove(key);
			}
		}
		return null;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see java.util.Map#putAll(java.util.Map)
	 */
	public void putAll(final Map<? extends K, ? extends V> m) {
		throw new UnsupportedOperationException("the putAll() method was not supported");
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see java.util.Map#clear()
	 */
	public void clear() {
		for (final Map<K, V> map : maps) {
			map.clear();
		}
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see java.util.Map#keySet()
	 */
	public Set<K> keySet() {
		final Set<K> result = new HashSet<K>();
		for (final Map<K, V> map : maps) {
			result.addAll(map.keySet());
		}
		return result;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see java.util.Map#values()
	 */
	public Collection<V> values() {
		final Collection<V> result = new ArrayList<V>();
		for (final Map<K, V> map : maps) {
			result.addAll(map.values());
		}
		return result;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see java.util.Map#entrySet()
	 */
	public Set<java.util.Map.Entry<K, V>> entrySet() {
		final Map<K, V> result = new HashMap<K, V>();
		for (final Map<K, V> map : maps) {
			result.putAll(map);
		}
		return result.entrySet();
	}

}
